use std::str::FromStr;

use crate::cli::verify_input_file;
use clap::{Parser, Subcommand, command};

#[derive(Debug, Subcommand)]
pub enum SubTextCommand {
    #[command(about = "Signed a message with a private/shared key")]
    Sign(TextSignOpts),
    #[command(about = "Verify a signed message")]
    Verify(TextVerifyOpts),
    #[command(about = "generate key")]
    GenerateKey(GenerateKeyOpts),
}

#[derive(Debug, Parser)]
pub struct TextSignOpts {
    #[arg(short, long, help = "Encryption key", default_value = "-")]
    pub key: String,
    #[arg(short, long, help = "Input file", default_value = "-", value_parser = verify_input_file)]
    pub input: String,

    #[arg(short, long, default_value = "blake3", value_parser = parse_crypt_format)]
    pub format: TextSignFormat,
}

#[derive(Debug, Parser)]
pub struct TextVerifyOpts {
    #[arg(short, long, help = "Input file", default_value = "-", value_parser = verify_input_file)]
    pub input: String,

    #[arg(short, long, help = "Decryption key", default_value = "-", value_parser = verify_input_file)]
    pub key: String,
    #[arg(short, long, help = "sig", default_value = "-", value_parser = verify_input_file)]
    pub sig: String,
    #[arg(short, long, default_value = "blake3", value_parser = parse_crypt_format)]
    pub format: TextSignFormat,
}

#[derive(Debug, Parser)]
pub struct GenerateKeyOpts {
    #[arg(short, long, default_value = "blake3")]
    pub format: TextSignFormat,
}

#[derive(Debug, Clone)]
pub enum TextSignFormat {
    Blake3,
    Ed25519,
}

fn parse_crypt_format(s: &str) -> Result<TextSignFormat, String> {
    s.parse()
}

impl FromStr for TextSignFormat {
    type Err = String;

    fn from_str(name: &str) -> Result<Self, Self::Err> {
        match name.to_lowercase().as_str() {
            "blake3" => Ok(TextSignFormat::Blake3),
            "ed25519" => Ok(TextSignFormat::Ed25519),
            _ => Err(format!("Invalid format: {}", name)),
        }
    }
}
